package com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.factory;

import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.annotation.PriceRegion;
import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.entity.CaclPrice;
import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.entity.OridnaryCustomer;
import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.entity.SuperVipCustomer;
import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.entity.VipCustomer;
import com.sheepjin.design_pattern.结合使用设计模式.策略_工厂_模板.intf.Price;
import com.sun.tools.javac.code.Attribute;
import org.reflections.Reflections;

import java.math.BigDecimal;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author： SheepJin
 * @date： 2022/6/10 - 11:46
 * @description：工厂模式，用于注册所有策略和获取策略
 * @modifiedBy：
 */
public class PriceStrategyFactory {

    /**
     * 策略工厂
     */
    public static PriceStrategyFactory PRICE_STRATEGY_FACTORY = new PriceStrategyFactory();

    /**
     * 价格策略集合
     */
    public List<Class<? extends Price>> priceStrategyList;

    /**
     * 通过无参构造来初始化价格策略工厂
     * </p>
     * springboot的方式可以直接将策略类指定为组件
     * 现在是通过注解获取策略类，并且注解可以携带一些业务数据
     */
    public PriceStrategyFactory() {
        //方式1：不推荐，增加策略需要修改此文件
        //priceStrategyList.add(OridnaryCustomer.class);
        //priceStrategyList.add(VipCustomer.class);
        //priceStrategyList.add(SuperVipCustomer.class);

        //方式2：自动扫描的方式
        //注意：Reflections所扫描的包路径不能包含中文，否则扫描不到
        Reflections reflections = new Reflections("com.sheepjin.design_pattern");
        Set<Class<?>> priceStrategyClasses = reflections.getTypesAnnotatedWith(PriceRegion.class);
        priceStrategyList = priceStrategyClasses.stream().map(clazz -> (Class<?extends Price>)clazz).collect(Collectors.toList());
    }

    /**
     * 通过价格存在的价格区间获取具体的价格策略
     * @param goodsPrice 商品价格
     * @return 价格计算策略
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    public Price getCustomerPriceByPriceStrategy(BigDecimal goodsPrice) throws InstantiationException, IllegalAccessException {
        for (Class<? extends Price> priceStrategyClass : priceStrategyList) {
            PriceRegion priceRegion = priceStrategyClass.getAnnotation(PriceRegion.class);
            if (goodsPrice.compareTo(new BigDecimal(priceRegion.max())) < 0
                    && goodsPrice.compareTo(new BigDecimal(priceRegion.min())) >= 0){
                return priceStrategyClass.newInstance();
            }
        }
        return null;
    }

    /**
     * 获取单例的价格策略工厂
     * @return 价格策略工厂
     */
    public static PriceStrategyFactory getInstance() {
        return PRICE_STRATEGY_FACTORY;
    }
}
